﻿#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
/// <summary>
/// 类型反射代码解析器
/// </summary>
public abstract class AbsESF_TypeReflexCodeResolver
{
    /// <summary>
    /// 唯一键值
    /// </summary>
    public string uniqueKey { get; private set; }

    /// <summary>
    /// 是否验证通过
    /// </summary>
    public bool isValidate { get; private set; }

    /// <summary>
    /// 是否属性
    /// </summary>
    public bool isProperty { get; private set; }

    /// <summary>
    /// 是否方法
    /// </summary>
    public bool isMethod { get; private set; }

    /// <summary>
    /// 是否字段
    /// </summary>
    public bool isField { get; private set; }

    /// <summary>
    /// 属性
    /// </summary>
    public PropertyInfo property { get; private set; }

    /// <summary>
    /// 方法
    /// </summary>
    public MethodInfo method { get; private set; }

    /// <summary>
    /// 字段
    /// </summary>
    public FieldInfo field { get; private set; }

    /// <summary>
    /// 属性可写
    /// </summary>
    public bool propertyCanWrite { get; private set; }

    /// <summary>
    /// 属性可读
    /// </summary>
    public bool propertyCanRead { get; private set; }

    /// <summary>
    /// 属性get方法名称
    /// </summary>
    public string propertyGetMethodNameCode { get; private set; }

    /// <summary>
    /// 属性set方法名称
    /// </summary>
    public string propertySetMethodNameCode { get; private set; }

    /// <summary>
    /// 访问关键字
    /// </summary>
    public string accessKeyword { get; private set; }

    /// <summary>
    /// 包含Override关键字
    /// </summary>
    public bool hasOverride { get; private set; }

    /// <summary>
    /// 是否有Base方法或属性
    /// </summary>
    public bool hasBase { get; private set; }

    /// <summary>
    /// override关键字
    /// </summary>
    public string overrideKeyword { get; private set; }

    /// <summary>
    /// 是否有返回值
    /// </summary>
    public bool hasReturn { get; private set; }

    /// <summary>
    /// 返回类型代码
    /// </summary>
    public string returnCode { get; private set; }

    /// <summary>
    /// 名称代码
    /// </summary>
    public string nameCode { get; private set; }

    /// <summary>
    /// 形参组[Key:名称,Value:类型]
    /// </summary>
    public Dictionary<string, string> formalParameters { get; private set; }
    /// <summary>
    /// 泛型参数
    /// </summary>
    public Dictionary<string, string> genericArguments { get; private set; }
    /// <summary>
    /// 参数使用In,Out,Ref关键字
    /// </summary>
    public bool useInOutRefParam { get; private set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="_property">属性</param>
    public AbsESF_TypeReflexCodeResolver(PropertyInfo _property)
    {
        property = _property;
        OnResolve();
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="_method">方法</param>
    public AbsESF_TypeReflexCodeResolver(MethodInfo _method)
    {
        method = _method;
        OnResolve();
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="_fieldInfo">字段</param>
    public AbsESF_TypeReflexCodeResolver(FieldInfo _fieldInfo)
    {
        field = _fieldInfo;
        OnResolve();
    }

    /// <summary>
    /// 解析
    /// </summary>
    void OnResolve()
    {
        //Virtual | Abstract | SpecialName
        //Virtual |  SpecialName
        //Virtual |  Abstract | SpecialName
        //Final | Virtual | SpecialName

        formalParameters = new Dictionary<string, string>();
        genericArguments = new Dictionary<string, string>();
        useInOutRefParam = false;
        isProperty = property != null;
        isMethod = method != null;
        isField = field != null;       
        if (isField)
        {
            nameCode = field.Name;
        }
        else if (isProperty)
        {
            accessKeyword = property.GetCSharpAccessKeyword();
            hasOverride = property.IsCSharpOverride()
                && !((property.GetCSharpMethodAttributes() & MethodAttributes.Final) == MethodAttributes.Final);

            hasBase = !property.DeclaringType.IsInterface;
            if (!property.DeclaringType.IsInterface)
            {
                overrideKeyword = hasOverride ? enESF_CSharpKeyword.overrideKeyword.ESF_FirstAttribute<ESF_AliasTooltipAttribute>().alias : enESF_CSharpKeyword.newKeyword.ESF_FirstAttribute<ESF_AliasTooltipAttribute>().alias;
                if (property.IsCSharpPrivate())
                {
                    overrideKeyword = string.Empty;
                }
            }

            returnCode = property.GetCSharpReturnParameterTypeName();
            nameCode = property.Name;

            hasReturn = property.CanRead;
            uniqueKey = $"{accessKeyword}_{overrideKeyword}_{returnCode}_{nameCode}_{formalParameters.ESF_Join(enESF_SeparatorSymbol.Underline).ESF_OnlyCNUAndOtherReplaceU()}".GetHashCode().ToString().ESF_OnlyCNUAndOtherReplaceU();

            if (property.GetMethod != null)
            {
                propertyGetMethodNameCode = property.GetMethod.Name;
            }

            if (property.SetMethod != null)
            {
                propertySetMethodNameCode = property.SetMethod.Name;
            }

            propertyCanWrite = property.CanWrite;
            propertyCanRead = property.CanRead;
        }
        else if (isMethod)
        {
            accessKeyword = method.GetCSharpAccessKeyword();
            hasOverride = method.IsCSharpOverride()
                && !((method.GetCSharpMethodAttributes() & MethodAttributes.Final) == MethodAttributes.Final);

            hasBase = !method.DeclaringType.IsInterface;
            if (!method.DeclaringType.IsInterface)
            {
                overrideKeyword = hasOverride ? enESF_CSharpKeyword.overrideKeyword.ESF_FirstAttribute<ESF_AliasTooltipAttribute>().alias : enESF_CSharpKeyword.newKeyword.ESF_FirstAttribute<ESF_AliasTooltipAttribute>().alias;
                if (method.IsCSharpPrivate())
                {
                    overrideKeyword = string.Empty;
                }
            }

            returnCode = method.GetCSharpReturnParameterTypeName();
            nameCode = method.Name;            
            hasReturn = !enESF_CSharpKeyword.voidKeyword.ESF_FirstAttribute<ESF_AliasTooltipAttribute>().alias.Equals(returnCode.ToLower());
            ParameterInfo[] pams = method.GetParameters();            
            if (pams != null)
            {
                string typeCode = string.Empty;
                string parName = string.Empty;
                foreach (var key in pams)
                {                    
                    typeCode = key.ParameterType.GetCSharpTypeCode();
                    parName = $"_{key.Name}";
                    if (key.IsIn)
                    {
                        typeCode = Regex.Replace(typeCode, @"([\w|\W|_]+?)\&", "in $1 ");
                    }
                    else if (key.IsOut)
                    {
                        typeCode = Regex.Replace(typeCode, @"([\w|\W|_]+?)\&", "out $1 ");
                    }
                    useInOutRefParam |= key.IsIn | key.IsOut | key.ParameterType.IsByRef;
                    formalParameters.Add(parName, typeCode);
                }
            }
            Type[] genTypes = method.GetGenericArguments();
            if (genTypes != null && genTypes.Length > 0)
            {
                foreach (var k in genTypes)
                {
                    genericArguments.Add(k.Name, k.BaseType?.Name);
                }
            }
            uniqueKey = $"{accessKeyword}_{overrideKeyword}_{returnCode}_{nameCode}_{formalParameters.ESF_Join(enESF_SeparatorSymbol.Underline).ESF_OnlyCNUAndOtherReplaceU()}".GetHashCode().ToString().ESF_OnlyCNUAndOtherReplaceU();
        }

        isValidate = (isProperty || isMethod) && !nameCode.Equals("Finalize");
    }
}
#endif
